Skip to content

Blocks 布局

Blocks 是 Gradio 中的高级 API,它提供了比 Interface 更灵活的布局选项和更强大的交互能力。使用 Blocks,您可以创建复杂的多步骤应用,自定义组件的布局,并设置复杂的事件处理。

基本用法

Blocks 的基本用法如下:

python
import gradio as gr

with gr.Blocks() as demo:
    gr.Markdown("# 我的应用")
    
    with gr.Row():
        with gr.Column():
            input1 = gr.Textbox(label="输入1")
            input2 = gr.Number(label="输入2")
            button = gr.Button("提交")
        
        with gr.Column():
            output = gr.Textbox(label="结果")
    
    button.click(fn=process_inputs, inputs=[input1, input2], outputs=output)

demo.launch()

与 Interface 不同,Blocks 使用上下文管理器(with 语句)来定义界面结构,并允许您精确控制组件的布局和交互。

布局元素

Blocks 提供了多种布局元素来组织您的界面:

Row 和 Column

RowColumn 允许您创建水平和垂直排列的组件:

python
with gr.Blocks() as demo:
    with gr.Row():                # 水平排列
        text1 = gr.Textbox(label="左侧文本")
        text2 = gr.Textbox(label="右侧文本")
    
    with gr.Column():             # 垂直排列
        text3 = gr.Textbox(label="上方文本")
        text4 = gr.Textbox(label="下方文本")

Group

Group 允许您将相关组件分组在一起,并添加一个标题:

python
with gr.Blocks() as demo:
    with gr.Group():
        gr.Markdown("## 用户信息")
        name = gr.Textbox(label="姓名")
        age = gr.Number(label="年龄")

Tab

Tab 允许您创建标签页界面:

python
with gr.Blocks() as demo:
    with gr.Tabs():
        with gr.Tab("第一个标签"):
            gr.Markdown("这是第一个标签的内容")
            input1 = gr.Textbox(label="标签1输入")
        
        with gr.Tab("第二个标签"):
            gr.Markdown("这是第二个标签的内容")
            input2 = gr.Textbox(label="标签2输入")

Box (Accordion) 折叠面板

Accordion 允许您创建可折叠的面板:

python
with gr.Blocks() as demo:
    with gr.Accordion("点击展开高级选项"):
        option1 = gr.Checkbox(label="选项1")
        option2 = gr.Checkbox(label="选项2")

事件处理

Blocks 的一个主要优势是其灵活的事件处理系统。您可以定义组件之间的复杂交互,例如在用户与一个组件交互时更新另一个组件。

基本事件处理

最常见的事件是按钮点击:

python
def greet(name):
    return f"你好,{name}!"

with gr.Blocks() as demo:
    name_input = gr.Textbox(label="您的名字")
    greet_btn = gr.Button("问候")
    output = gr.Textbox(label="问候语")
    
    greet_btn.click(fn=greet, inputs=name_input, outputs=output)

多个事件源和目标

您可以连接多个输入和输出:

python
def full_name(first_name, last_name):
    return f"{last_name}{first_name}"

with gr.Blocks() as demo:
    first_name = gr.Textbox(label="名")
    last_name = gr.Textbox(label="姓")
    btn = gr.Button("生成全名")
    result = gr.Textbox(label="全名")
    
    btn.click(fn=full_name, inputs=[first_name, last_name], outputs=result)

事件类型

除了 click 外,不同组件还支持其他事件类型:

python
# 输入变化时触发
textbox.change(fn=function, inputs=[...], outputs=[...])

# 组件获得焦点时触发
textbox.focus(fn=function, inputs=[...], outputs=[...])

# 组件失去焦点时触发
textbox.blur(fn=function, inputs=[...], outputs=[...])

# 提交时触发 (按回车键)
textbox.submit(fn=function, inputs=[...], outputs=[...])

使用 update 函数动态修改组件

Gradio 提供了 update 函数来动态更改组件属性:

python
def update_dropdown(choice):
    if choice == "水果":
        return gr.Dropdown.update(choices=["苹果", "香蕉", "橙子"])
    else:
        return gr.Dropdown.update(choices=["黄瓜", "茄子", "西红柿"])

with gr.Blocks() as demo:
    category = gr.Radio(["水果", "蔬菜"], label="类别")
    items = gr.Dropdown(label="物品")
    
    category.change(fn=update_dropdown, inputs=category, outputs=items)

状态管理

使用 State 组件保存状态

State 组件允许您在会话中存储不显示在界面上的数据:

python
def add_to_history(message, history):
    history = history + [(message, f"回复: {message}")]
    return "", history  # 清空输入框,更新历史记录

with gr.Blocks() as demo:
    chatbot = gr.Chatbot(label="聊天历史")
    msg = gr.Textbox(label="消息")
    chat_history = gr.State([])  # 状态变量,不显示在界面上
    
    msg.submit(fn=add_to_history, inputs=[msg, chat_history], outputs=[msg, chatbot])

高级用法

预处理和后处理函数

您可以添加多个函数串联处理:

python
def preprocess(text):
    return text.lower()

def process(text):
    return text.upper()

def postprocess(text):
    return f"处理结果: {text}"

with gr.Blocks() as demo:
    text_in = gr.Textbox(label="输入")
    btn = gr.Button("处理")
    text_out = gr.Textbox(label="输出")
    
    btn.click(fn=preprocess, inputs=text_in, outputs=gr.Textbox()).then(
        fn=process, outputs=gr.Textbox()).then(
        fn=postprocess, outputs=text_out)

自定义 JavaScript 交互

您可以添加自定义 JavaScript 函数处理交互:

python
with gr.Blocks() as demo:
    text = gr.Textbox()
    btn = gr.Button("转换")
    output = gr.Textbox()
    
    btn.click(
        fn=None,  # 没有 Python 函数
        inputs=text,
        outputs=output,
        _js="""
        function(text) {
            return text.toUpperCase();
        }
        """
    )

动态添加和删除组件

Blocks API 还允许动态添加和删除组件:

python
def create_textbox():
    return gr.Textbox(label="新文本框", interactive=True)

with gr.Blocks() as demo:
    with gr.Column() as col:
        text = gr.Textbox(label="已有文本框")
    
    add_btn = gr.Button("添加新文本框")
    add_btn.click(fn=create_textbox, inputs=None, outputs=col)

示例应用

交互式图像处理应用

python
import gradio as gr
import numpy as np
from PIL import Image, ImageEnhance, ImageFilter

def adjust_image(image, brightness, contrast, blur):
    img = Image.fromarray(image)
    
    # 调整亮度
    if brightness != 1:
        enhancer = ImageEnhance.Brightness(img)
        img = enhancer.enhance(brightness)
    
    # 调整对比度
    if contrast != 1:
        enhancer = ImageEnhance.Contrast(img)
        img = enhancer.enhance(contrast)
    
    # 应用模糊
    if blur > 0:
        img = img.filter(ImageFilter.GaussianBlur(radius=blur))
    
    return np.array(img)

with gr.Blocks() as demo:
    gr.Markdown("# 图像编辑器")
    
    with gr.Row():
        with gr.Column():
            input_image = gr.Image(label="原始图像")
            with gr.Row():
                brightness = gr.Slider(0.5, 2.0, value=1, label="亮度")
                contrast = gr.Slider(0.5, 2.0, value=1, label="对比度")
            blur = gr.Slider(0, 10, value=0, label="模糊")
            process_btn = gr.Button("处理")
        
        with gr.Column():
            output_image = gr.Image(label="处理后图像")
    
    process_btn.click(
        fn=adjust_image,
        inputs=[input_image, brightness, contrast, blur],
        outputs=output_image
    )
    
    # 实时处理
    input_image.change(
        fn=adjust_image,
        inputs=[input_image, brightness, contrast, blur],
        outputs=output_image
    )
    brightness.change(
        fn=adjust_image,
        inputs=[input_image, brightness, contrast, blur],
        outputs=output_image
    )
    contrast.change(
        fn=adjust_image,
        inputs=[input_image, brightness, contrast, blur],
        outputs=output_image
    )
    blur.change(
        fn=adjust_image,
        inputs=[input_image, brightness, contrast, blur],
        outputs=output_image
    )

demo.launch()

多步骤表单应用

python
import gradio as gr

def validate_step1(name, email):
    if not name:
        return gr.update(visible=True), gr.update(visible=False, value=None)
    if "@" not in email:
        return gr.update(visible=True), gr.update(visible=False, value=None)
    return gr.update(visible=False), gr.update(visible=True)

def submit_form(name, email, age, feedback):
    return f"表单已提交!\n姓名: {name}\n邮箱: {email}\n年龄: {age}\n反馈: {feedback}"

with gr.Blocks() as demo:
    gr.Markdown("# 多步骤表单")
    
    name = gr.Textbox(label="姓名")
    email = gr.Textbox(label="邮箱")
    next_btn = gr.Button("下一步")
    error_box = gr.Markdown(visible=False, value="请填写所有必填字段!")
    
    with gr.Group(visible=False) as step2:
        age = gr.Number(label="年龄")
        feedback = gr.Textbox(label="反馈", lines=3)
        submit_btn = gr.Button("提交")
    
    result = gr.Textbox(label="结果", visible=False)
    
    next_btn.click(
        fn=validate_step1,
        inputs=[name, email],
        outputs=[error_box, step2]
    )
    
    submit_btn.click(
        fn=submit_form,
        inputs=[name, email, age, feedback],
        outputs=result
    )

demo.launch()

总结

Blocks API 提供了比 Interface 更灵活的方式来构建 Gradio 应用。它允许您:

  1. 精确控制组件的布局和排列
  2. 创建复杂的事件处理和组件交互
  3. 设计多步骤的应用流程
  4. 管理状态和数据流
  5. 自定义前端行为和外观

虽然 Blocks 比 Interface 更复杂,但它提供了更大的灵活性,使您能够构建功能丰富的应用,如对话机器人、多步骤表单、交互式仪表板等。

在下一章中,我们将介绍 ChatInterface,这是一个专门为构建聊天应用而设计的高级接口。